"""
Django 数据库适配层
用于在异步环境中使用 Django ORM

由于 Django ORM 默认是同步的，而 NoneBot 是异步框架，
我们需要使用 asgiref.sync.sync_to_async 来将同步操作转换为异步操作
"""
import os
import sys
from typing import Any, Dict, List, Optional, Tuple

# 设置 Django 环境
# 需要在使用 Django ORM 之前设置
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.insert(0, BASE_DIR)

# 设置 Django 设置模块
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_project.settings')

# 初始化 Django（只需要执行一次）
import django
django.setup()

# 现在可以导入 Django 的模型了
from asgiref.sync import sync_to_async
from datetime import datetime, timezone
from django.utils import timezone as django_timezone
from xiaoyibot_app.models import (
    UserNickname,
    MessageRecord,
    Group,
    GroupMember,
)


# ==================== 异步适配函数 ====================

async def get_or_create_user_nickname(qq_number: int, nickname: str, default_status: int = 1):
    """
    获取或创建用户群名片记录（异步版本）
    
    如果记录已存在，返回已有记录，不会更新
    如果记录不存在，创建新记录
    
    Args:
        qq_number: QQ号
        nickname: 群名片
        default_status: 默认状态，默认为1
        
    Returns:
        (UserNickname对象, 是否是新创建的) 元组
    """
    @sync_to_async
    def _get_or_create():
        return UserNickname.objects.get_or_create(
            qq_number=qq_number,
            defaults={
                'nickname': nickname,
                'status': default_status
            }
        )
    
    return await _get_or_create()


async def batch_create_user_nicknames(data_list: list) -> int:
    """
    批量创建用户群名片记录（异步版本）
    
    如果记录已存在（根据主键 qq_number），则跳过，不更新已有记录
    
    Args:
        data_list: 数据列表，每个元素是 (qq_number, nickname) 元组
        
    Returns:
        成功插入的记录数
    """
    @sync_to_async
    def _batch_create():
        if not data_list:
            return 0
        
        # 使用 bulk_create 的 ignore_conflicts 参数来实现类似 INSERT IGNORE 的效果
        objects_to_create = []
        
        for qq_number, nickname in data_list:
            objects_to_create.append(
                UserNickname(
                    qq_number=qq_number,
                    nickname=nickname,
                    status=1
                )
            )
        
        # 分批处理，避免一次性插入太多数据
        batch_size = 300
        total_inserted = 0
        
        for i in range(0, len(objects_to_create), batch_size):
            batch = objects_to_create[i:i + batch_size]
            # 批量创建，ignore_conflicts=True 表示如果主键冲突则忽略
            created = UserNickname.objects.bulk_create(
                batch,
                ignore_conflicts=True
            )
            total_inserted += len(created)
        
        return total_inserted
    
    return await _batch_create()


async def get_user_nicknames_by_qq_numbers(qq_numbers: list) -> dict:
    """
    批量获取用户群名片（异步版本）
    
    Args:
        qq_numbers: QQ号列表
        
    Returns:
        Dict[qq_number, nickname] 格式的字典，只包含数据库中存在的QQ号
    """
    @sync_to_async
    def _get_nicknames():
        # 查询所有匹配的QQ号，且状态为1的记录
        users = UserNickname.objects.filter(
            qq_number__in=qq_numbers,
            status=1
        ).values('qq_number', 'nickname')
        
        # 转换为字典格式
        return {user['qq_number']: user['nickname'] for user in users}
    
    return await _get_nicknames()


async def get_user_nickname(qq_number: int) -> Optional[UserNickname]:
    """
    获取单个用户群名片（异步版本）
    
    Args:
        qq_number: QQ号
        
    Returns:
        UserNickname 对象，如果不存在则返回 None
    """
    @sync_to_async
    def _get_user():
        try:
            return UserNickname.objects.get(qq_number=qq_number, status=1)
        except UserNickname.DoesNotExist:
            return None
    
    return await _get_user()


async def update_user_nickname(qq_number: int, nickname: str) -> bool:
    """
    更新用户群名片（异步版本）
    
    Args:
        qq_number: QQ号
        nickname: 新的群名片
        
    Returns:
        是否更新成功
    """
    @sync_to_async
    def _update_user():
        try:
            user = UserNickname.objects.get(qq_number=qq_number)
            user.nickname = nickname
            user.save()
            return True
        except UserNickname.DoesNotExist:
            return False
    
    return await _update_user()


async def delete_user_nickname(qq_number: int) -> bool:
    """
    删除用户群名片（软删除，设置status为0）
    
    Args:
        qq_number: QQ号
        
    Returns:
        是否删除成功
    """
    @sync_to_async
    def _delete_user():
        try:
            user = UserNickname.objects.get(qq_number=qq_number)
            user.status = 0
            user.save()
            return True
        except UserNickname.DoesNotExist:
            return False
    
    return await _delete_user()


# ==================== 消息记录相关函数 ====================

def parse_qq_timestamp(timestamp: float) -> datetime:
    """
    将 QQ 时间戳转换为 UTC datetime 对象
    
    QQ 的 event.time 是 UTC 时间戳（Unix 时间戳），
    需要明确指定时区为 UTC，Django 会自动处理时区转换。
    
    Args:
        timestamp: QQ 事件的时间戳（UTC 时间戳）
        
    Returns:
        带 UTC 时区的 datetime 对象
    """
    return datetime.fromtimestamp(timestamp, tz=timezone.utc)


async def create_message_record(
    qq_message_id: int,
    sender_qq: int,
    message_content: str,
    message_time: datetime,
    group_id: Optional[int] = None,
    message_type: str = 'group',
    raw_message: Optional[Dict[str, Any]] = None
) -> MessageRecord:
    """
    创建消息记录（异步版本）
    
    Args:
        qq_message_id: QQ消息的唯一ID
        sender_qq: 发送者QQ号
        message_content: 消息文本内容
        message_time: 消息发送时间
        group_id: 群号（群消息时必需，私聊时为None）
        message_type: 消息类型（'group' 或 'private'）
        raw_message: 原始消息JSON（可选）
        
    Returns:
        MessageRecord 对象
    """
    @sync_to_async
    def _create():
        return MessageRecord.objects.create(
            qq_message_id=qq_message_id,
            sender_qq=sender_qq,
            group_id=group_id,
            message_type=message_type,
            message_content=message_content,
            raw_message=raw_message,
            message_time=message_time
        )
    
    return await _create()


async def get_messages_by_group(
    group_id: int,
    limit: int = 100,
    offset: int = 0
) -> List[MessageRecord]:
    """
    获取指定群的消息记录（异步版本）
    
    Args:
        group_id: 群号
        limit: 返回数量限制
        offset: 偏移量（用于分页）
        
    Returns:
        MessageRecord 对象列表
    """
    @sync_to_async
    def _get_messages():
        return list(
            MessageRecord.objects
            .filter(group_id=group_id, message_type='group')
            .order_by('-message_time')
            [offset:offset + limit]
        )
    
    return await _get_messages()


async def get_messages_by_sender(
    sender_qq: int,
    group_id: Optional[int] = None,
    limit: int = 100,
    offset: int = 0
) -> List[MessageRecord]:
    """
    获取指定发送者的消息记录（异步版本）
    
    Args:
        sender_qq: 发送者QQ号
        group_id: 群号（可选，如果指定则只查询该群的消息）
        limit: 返回数量限制
        offset: 偏移量（用于分页）
        
    Returns:
        MessageRecord 对象列表
    """
    @sync_to_async
    def _get_messages():
        queryset = MessageRecord.objects.filter(sender_qq=sender_qq)
        if group_id is not None:
            queryset = queryset.filter(group_id=group_id)
        return list(
            queryset
            .order_by('-message_time')
            [offset:offset + limit]
        )
    
    return await _get_messages()


async def get_message_by_id(message_id: int) -> Optional[MessageRecord]:
    """
    根据数据库ID获取消息记录（异步版本）
    
    Args:
        message_id: 数据库记录ID
        
    Returns:
        MessageRecord 对象，如果不存在则返回 None
    """
    @sync_to_async
    def _get_message():
        try:
            return MessageRecord.objects.get(id=message_id)
        except MessageRecord.DoesNotExist:
            return None
    
    return await _get_message()


async def get_message_by_qq_message_id(qq_message_id: int) -> Optional[MessageRecord]:
    """
    根据QQ消息ID获取消息记录（异步版本）
    
    Args:
        qq_message_id: QQ消息的唯一ID
        
    Returns:
        MessageRecord 对象，如果不存在则返回 None
    """
    @sync_to_async
    def _get_message():
        try:
            return MessageRecord.objects.get(qq_message_id=qq_message_id)
        except MessageRecord.DoesNotExist:
            return None
        except MessageRecord.MultipleObjectsReturned:
            # 如果有多条记录，返回最新的
            return MessageRecord.objects.filter(qq_message_id=qq_message_id).order_by('-message_time').first()
    
    return await _get_message()


async def mark_message_recalled(
    qq_message_id: int,
    recalled_at: Optional[datetime] = None
) -> bool:
    """
    标记消息为已撤回（异步版本）
    
    Args:
        qq_message_id: QQ消息的唯一ID
        recalled_at: 撤回时间（如果为None，则使用当前时间）
        
    Returns:
        是否更新成功
    """
    @sync_to_async
    def _mark_recalled():
        try:
            message = MessageRecord.objects.get(qq_message_id=qq_message_id)
            message.is_recalled = True
            message.recalled_at = recalled_at or django_timezone.now()
            message.save()
            return True
        except MessageRecord.DoesNotExist:
            return False
    
    return await _mark_recalled()


async def get_message_count_by_group(group_id: int) -> int:
    """
    获取指定群的消息总数（异步版本）
    
    Args:
        group_id: 群号
        
    Returns:
        消息总数
    """
    @sync_to_async
    def _get_count():
        return MessageRecord.objects.filter(
            group_id=group_id,
            message_type='group'
        ).count()
    
    return await _get_count()


async def search_messages(
    keyword: str,
    group_id: Optional[int] = None,
    limit: int = 100,
    offset: int = 0
) -> List[MessageRecord]:
    """
    搜索消息内容（异步版本）
    
    Args:
        keyword: 搜索关键词
        group_id: 群号（可选，如果指定则只搜索该群的消息）
        limit: 返回数量限制
        offset: 偏移量（用于分页）
        
    Returns:
        MessageRecord 对象列表
    """
    @sync_to_async
    def _search():
        queryset = MessageRecord.objects.filter(message_content__icontains=keyword)
        if group_id is not None:
            queryset = queryset.filter(group_id=group_id)
        return list(
            queryset
            .order_by('-message_time')
            [offset:offset + limit]
        )
    
    return await _search()


# ==================== 分组管理相关函数 ====================


async def list_groups() -> List[Group]:
    """
    获取所有分组列表
    """

    @sync_to_async
    def _list():
        return list(Group.objects.all())

    return await _list()


async def get_group_by_name(name: str) -> Optional[Group]:
    """
    根据 name 获取分组
    """

    @sync_to_async
    def _get():
        try:
            return Group.objects.get(name=name)
        except Group.DoesNotExist:
            return None

    return await _get()


async def create_group(
    name: str,
    display_name: str = "",
    description: str = ""
) -> Tuple[Group, bool]:
    """
    创建分组（若存在则返回已有）
    """

    @sync_to_async
    def _create():
        return Group.objects.get_or_create(
            name=name,
            defaults={
                "display_name": display_name or "",
                "description": description or "",
            },
        )

    return await _create()


async def add_member_to_group(
    group: Group,
    qq_id: int,
    qq_nickname: str = "",
) -> Tuple[GroupMember, bool]:
    """
    将成员加入分组
    """

    @sync_to_async
    def _add():
        member, created = GroupMember.objects.get_or_create(
            group=group,
            qq_id=qq_id,
            defaults={"qq_nickname": qq_nickname or ""},
        )
        if (not created) and qq_nickname and member.qq_nickname != qq_nickname:
            member.qq_nickname = qq_nickname
            member.save(update_fields=["qq_nickname"])
        return member, created

    return await _add()


async def delete_group(name: str) -> bool:
    """
    删除分组（同时删除该分组下的所有成员）
    返回是否删除成功
    """
    @sync_to_async
    def _delete():
        try:
            group = Group.objects.get(name=name)
            # 删除分组会自动删除关联的成员（因为外键设置了 CASCADE）
            group.delete()
            return True
        except Group.DoesNotExist:
            return False
    
    return await _delete()


async def remove_member_from_group(qq_id: int, group_name: Optional[str] = None) -> int:
    """
    删除成员
    - 如果指定了 group_name，只删除该成员在该组的信息
    - 如果没有指定 group_name，删除该成员在所有组的信息
    
    返回删除的记录数
    """
    @sync_to_async
    def _remove():
        if group_name:
            # 只删除指定组的成员
            try:
                group = Group.objects.get(name=group_name)
                deleted_count, _ = GroupMember.objects.filter(
                    group=group,
                    qq_id=qq_id
                ).delete()
                return deleted_count
            except Group.DoesNotExist:
                return 0
        else:
            # 删除所有组的成员
            deleted_count, _ = GroupMember.objects.filter(qq_id=qq_id).delete()
            return deleted_count
    
    return await _remove()


async def get_group_members(group_name: str) -> List[GroupMember]:
    """
    获取指定分组的所有成员列表
    """
    @sync_to_async
    def _get_members():
        try:
            group = Group.objects.get(name=group_name)
            return list(GroupMember.objects.filter(group=group).order_by('added_at'))
        except Group.DoesNotExist:
            return []
    
    return await _get_members()

